/** AMENDMENTS:
 * DATE       	NAME    	VERSION     DESCRIPTION
 * --------     -----  		-------     -----------
 * 20/03/2013   Michael		1.0.0       1.SystemLogManager
**/
package com.map.manager;

import java.io.FileWriter;
import java.io.PrintWriter;
import java.text.DateFormat;
import java.util.Calendar;
import java.util.Date;

/**
 * SystemLogManager is implemented as a variant of a Singleton
 * which controls logging of error messages and warnings to the system log.
 * The location of the system log is determined by the "SysLogFile" entry in
 * the <i>system.properties</i> file. If no such entry is defined, then it will create and log to
 * the file <i>system.log</i> in the current working directory.
 * <p>
 * Usage of this class assumes that the ConfigManager class has been
 * loaded with the properties from the config file.
 * <p>
 */
public class SystemLogManager {
	private static PrintWriter log = null;
	private static String logFile = null;
	private static SystemLogManager instance = null;

	private static final String defaultFilePath = "/system.log";

	private SystemLogManager() {
		super();
	}

    /**
     * Returns the single instance, creating one if it's the
     * first time this method is called.
     *
     * @return SystemLogManager. The single instance.
     */
	public static SystemLogManager getInstance() {
		//thread-safe implementation
		if (instance == null) {
			synchronized (SystemLogManager.class) {
				if (instance == null) {
					instance = new SystemLogManager();
					if ((logFile = ConfigManager.getInstance().get("SysLogFile")) == null) {
						logFile = defaultFilePath;
					}
					System.out.println("logfile system path:" + logFile);
				}
			}
		}
		return instance;
	}

	/**
     * Logs error messages to the log
     *
     * @param EnhancedException The necessary information regarding the error
     * would be retrieved from the EnhancedException object. This includes the
     * exception location in the code (which class, which method, etc), and
     * extra error messages.
     * <p>
     * Ordinarily, this is coded as follows:
     * <p><pre><code>
     * try {
	 *     //statements
     * } catch (Exception e) {
     *     EnhancedException ex = new EnhancedException(e.getMessage());
     *     ex.setExceptionLocation("className_methodName_###");
     *     ex.setExtraMessage("any extra message that will be helpful");
     *     SystemLogManager.getInstance().logError(ex);
     * }
     * </code></pre>
     * <p>
     * If logging does not occur within a catch block, then the EnhancedException
     * should be created with an empty string ("").
     */
	public void logError(Throwable e) {
		String extraMessage = "";
		if (e != null) {
			StringBuffer content = new StringBuffer(e.toString());
			StackTraceElement[] eles = e.getStackTrace();
			if (eles != null) {
				for (int i=0; i<eles.length; i++) {
					StackTraceElement sck = eles[i];
					content.append("    at  " + sck.getClassName()
							+ "." + sck.getMethodName());
					content.append("(" + sck.getFileName() + ":"
							+ sck.getLineNumber() + ")");
					content.append("\n");
				}
			}

			extraMessage =	content.toString();
		}
		log("ERROR", extraMessage, null);
	}
	
	/**
     * Logs info or status messages to the log
     *
     * @param message The info message to be logged
     */
	public void logMsg(String msg) {
		log("INFO", msg, null);
	}

	private void getResources() throws Exception {
		//set with file write append (second boolean parameter)
		//set without autoflush in PrintWriter
		log = new PrintWriter(new FileWriter(logFile, true));
	}

	private void releaseResources() {
		if (log != null)
			log.close();
	}

	//NOTE: As long as ALL modifications to the content of the log is done
	//      through this synchronized method, there is no need to synchronize
	//      the rest of the methods.

	private synchronized void log(String location,
		String extraMessage, String mainMessage) {

		Date todaysDate = Calendar.getInstance().getTime();
		DateFormat df = DateFormat.getDateTimeInstance(DateFormat.LONG,
			DateFormat.SHORT);
		try {
			getResources();
			//logging of error messages that do not contain a thrown exception
			if ((mainMessage == null) || (mainMessage.length() < 1)) {
				log.println("[" + df.format(todaysDate) + "] (" +
					location + ") : " +
					extraMessage);
			}
			//logging of error messages that encapsulates a thrown exception
			else {
				log.println("[" + df.format(todaysDate) + "] (" +
					location + ") : " +
					extraMessage + " | " +
					"(" + mainMessage + ")");

			}
			log.flush();
		} catch (Exception e) {
			System.out.println(e.getMessage());
			e.printStackTrace();
		}
		releaseResources();
	}
}
